﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Data;

namespace Cryomancer.StarChart
{
	[ValueConversion(typeof(double), typeof(string))]
	public class ArcMinToDegreesConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			int degrees = (int)Math.Floor((double)value / 60);
			int minutes = (int)Math.Floor((double)value % 60);

			string retVal = String.Format("{0}\u00B0 {1}'", degrees, minutes);
			return retVal;
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}

		#endregion
	}

	[ValueConversion(typeof(double), typeof(string))]
	public class DecimalToDegreesConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			double fraction = 0.0;

			int degrees = (int)Math.Floor((double)value);

			fraction = (double)value - (double)degrees;
			int minutes = (int)Math.Floor(fraction * 60.0);


			int seconds = (int)Math.Floor((double)value % 3600);

			string retVal = String.Format("{0}\u00B0 {1}'", degrees, minutes);
			return retVal;
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}

		#endregion
	}

	[ValueConversion(typeof(double), typeof(string))]
	public class SingleDecimalConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return String.Format("{0:F1}", value);
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}

		#endregion
	}

	[ValueConversion(typeof(double), typeof(string))]
	public class IntegerConveter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return String.Format("{0}", (int)Math.Truncate((double)value));
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}

		#endregion
	}

	public class RARangeRule : ValidationRule
	{
		#region Methods
		public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
		{
			string rawVal = value as String;
			if (rawVal == null)
			{
				return new ValidationResult(false, "Value is not a string.");
			}

			string[] parts = rawVal.Split(' ', ':');
			if (parts.Length != 3)
			{
				return new ValidationResult(false, "Value is not in the format of 'xx:MM:SS.S' or 'xx MM SS.S'");
			}

			ValidationResult hourResult = CheckTimeslice(parts[0], "Hours", 23);
			if (!hourResult.IsValid)
			{
				return hourResult;
			}
			
			ValidationResult minResult = CheckTimeslice(parts[1], "Minutes", 59);
			if (!minResult.IsValid)
			{
				return minResult;
			}

			ValidationResult secResult = CheckTimeslice(parts[2], "Seconds", 59);
			if (!secResult.IsValid)
			{
				return secResult;
			}

			return ValidationResult.ValidResult;
		}

		internal static ValidationResult CheckTimeslice(string value, string part, double max)
		{
			double result;
			if (!Double.TryParse(value, out result))
			{
				return new ValidationResult(false, String.Format("'{0}' must be a numeric value.", part));
			}

			if (result < 0 || result > max)
			{
				return new ValidationResult(
					false, 
					String.Format("'{0}' must be in the range of 0 to {1}.", 
						part, 
						(int)Math.Truncate((double)max))); 
			}

			return ValidationResult.ValidResult;
		}
		#endregion
	}

	public class DecRangeRule : ValidationRule
	{
		public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
		{
			string rawVal = value as String;
			if (rawVal == null)
			{
				return new ValidationResult(false, "Value is not a string.");
			}

			string[] parts = rawVal.Split(' ', ':');
			if (parts.Length != 3)
			{
				return new ValidationResult(false, "Value is not in the format of 'xx:MM:SS.S' or 'xx MM SS.S'");
			}

			ValidationResult hourResult = CheckTimeslice(parts[0], "Degrees", -90, 90);
			if (!hourResult.IsValid)
			{
				return hourResult;
			}
			
			ValidationResult minResult = CheckTimeslice(parts[1], "Minutes", 59);
			if (!minResult.IsValid)
			{
				return minResult;
			}

			ValidationResult secResult = CheckTimeslice(parts[2], "Seconds", 59);
			if (!secResult.IsValid)
			{
				return secResult;
			}

			return ValidationResult.ValidResult;
		}

		internal static ValidationResult CheckTimeslice(string value, string part, double max)
		{
			return CheckTimeslice(value, part, 0, max);
		}

		internal static ValidationResult CheckTimeslice(string value, string part, double min, double max)
		{
			double result;
			if (!Double.TryParse(value, out result))
			{
				return new ValidationResult(false, String.Format("'{0}' must be a numeric value.", part));
			}

			if (result < min || result > max)
			{
				return new ValidationResult(
					false, 
					String.Format("'{0}' must be in the range of {1} to {2}.", 
						part,
						(int)Math.Truncate((double)min),
						(int)Math.Truncate((double)max))); 
			}

			return ValidationResult.ValidResult;
		}
	}
}
